﻿using System;
using System.Collections.Generic;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;

namespace CrmLinkBuddyWpf
{
    internal class CrmRecordFinder
    {
        IOrganizationService _crmService;
        CrmMetadataRetriever _crmMetadataRetriever;
        List<string> _preferredEntities;
        List<string> _entitiesToQuery;

        /// <summary>
        /// A list of entity logical names that methods in this class should start with when searching for records.
        /// </summary>
        public List<string> PreferredEntities
        {
            get { return _preferredEntities; }
            set { _preferredEntities = value; }
        }

        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="serviceProxy">Authenticated instance of a CRM service connection</param>
        /// <param name="attributesMetadata">Attribute metadata DataTable</param>
        /// <param name="entitiesMetadata">Entities metadata DataTable</param>
        public CrmRecordFinder(IOrganizationService serviceProxy, CrmMetadataRetriever crmMetadataRetriever, List<string> entityLogicalNames)
        {
            _crmService = serviceProxy;
            _crmMetadataRetriever = crmMetadataRetriever;
            _entitiesToQuery = entityLogicalNames;

            _preferredEntities = new List<string>();
        }

        /// <summary>
        /// Details regarding the entity record found in CRM.
        /// </summary>
        internal struct RetrievedEntityRecord
        {
            internal Guid RecordId;
            internal string RecordPrimaryNameValue;
            internal string EntityLogicalName;
        }

        /// <summary>
        /// Query entity types in CRM for a primary key that matches the given GUID.
        /// </summary>
        /// <param name="guidToFindInCrm">A GUID that this method will use to find a matching record.</param>
        /// <returns>Instance of RetrievedEntityRecord</returns>
        internal RetrievedEntityRecord RetrieveRecordById(Guid guidToFindInCrm)
        {
            var retrievedData = new RetrievedEntityRecord();

            foreach (string entityName in _entitiesToQuery)
            {
                try
                {
                    string attributeToRetrieve = _crmMetadataRetriever.GetEntityPrimaryNameAttribute(entityName);
                    if (!string.IsNullOrEmpty(attributeToRetrieve))
                    {
                        QueryByAttribute query = new QueryByAttribute();
                        query.EntityName = entityName;
                        query.Attributes.Add(_crmMetadataRetriever.GetEntityPrimaryIdAttributeName(entityName));
                        query.Values.Add(guidToFindInCrm);
                        query.ColumnSet = new ColumnSet(new string[] { attributeToRetrieve });
                        RetrieveMultipleRequest request = new RetrieveMultipleRequest();
                        request.Query = query;

                        RetrieveMultipleResponse response = (RetrieveMultipleResponse)_crmService.Execute(request);
                        if (response.EntityCollection.Entities.Count == 1)
                        {
                            Entity entity = response.EntityCollection.Entities[0];

                            retrievedData.EntityLogicalName = entityName;
                            retrievedData.RecordId = entity.Id;
                            retrievedData.RecordPrimaryNameValue = entity.GetAttributeValue<string>(attributeToRetrieve);

                            break;
                        }
                    }

                }
                catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>)
                {
                    // Ignore; keep on going
                }
            }

            return retrievedData;
        }
    }
}
